
#include "StdAfx.h"
#include "ODBC_DBResultSet.h"
#include "DBService.h"

ODBC_DBResultSet::ODBC_DBResultSet(){
	bind_col_idx_ = 0;
	stmt_ = 0;
	current_result_col_pos_ = 0;	
	result_type_ = DEF_RESULT_TYPE_ROW;
}

ODBC_DBResultSet::~ODBC_DBResultSet(){
	reset();	
}

int ODBC_DBResultSet::next(){
	if(! stmt_ )
		return 0;

	SQLRETURN retCode = ::SQLFetchScroll( stmt_, SQL_FETCH_NEXT, 0 );

	if( retCode == SQL_NO_DATA_FOUND )
		return 0;

	if( retCode == SQL_INVALID_HANDLE )
		return 0;

	if( retCode == SQL_NULL_DATA )
		return 0;

	current_result_col_pos_ = 0;

	return 1;
}

void ODBC_DBResultSet::reset(){	
	current_result_col_pos_ = 0;	

	if( stmt_ ){		
		SQLFreeHandle((SQLSMALLINT)SQL_HANDLE_STMT, stmt_);		
		stmt_ = 0;
	}
}

char ODBC_DBResultSet::getByte(){
	bind_col_idx_ = 0;
	current_result_col_pos_++;

	char ret = 0;
	SQLLEN size = 0;

	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_CHAR, &ret, 0, &size );	

	return ret;
}

short ODBC_DBResultSet::get2Byte(){
	current_result_col_pos_++;
	
	short ret = 0;
	SQLLEN size = 0;

	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_SSHORT, &ret, 0, &size );	

	return ret;
}

int ODBC_DBResultSet::get4Byte(){
	current_result_col_pos_++;
	
	int ret = 0;
	SQLLEN size = 0;

	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_SLONG, &ret, 0, &size );	

	return ret;
}

__int64 ODBC_DBResultSet::get8Byte(){
	current_result_col_pos_++;
	
	__int64 ret = 0;
	SQLLEN size = 0;

	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_SBIGINT, &ret, 0, &size );	

	return ret;
}

int ODBC_DBResultSet::getString( char* buffer, size_t size ){
	current_result_col_pos_++;
	
	SQLLEN ret_size = 0;
	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_CHAR, buffer, size, &ret_size );

	return ret_size;
}

int ODBC_DBResultSet::getMemory( char* buffer, size_t size ){
	current_result_col_pos_++;
	
	SQLLEN ret_size = 0;
	int result = 0;

	result = ::SQLGetData( stmt_, current_result_col_pos_, SQL_C_BINARY, buffer, 0, &ret_size );
	if( result == SQL_SUCCESS_WITH_INFO ){		
		result = SQLGetData( stmt_, current_result_col_pos_, SQL_C_DEFAULT, &( buffer[ ret_size ] ), \
			ret_size, &ret_size );

		if( result != SQL_SUCCESS ){
			//err 
			return DEFAULT_FAIL;
		}
	}

	return ret_size;
}

double ODBC_DBResultSet::getFloat(){
	current_result_col_pos_++;
	
	double ret = 0;
	SQLLEN size = 0;

	::SQLGetData( stmt_, current_result_col_pos_, SQL_C_FLOAT, &ret, 0, &size );	

	return ret;
}

int ODBC_DBResultSet::makeHandle( DBSession* session, int result_type ){
	result_type_ = result_type;	

	SQLHDBC	hdbc = ((ODBC_DBSession*)session)->getSession();

	SQLRETURN retCode = ::SQLAllocHandle( (SQLSMALLINT)SQL_HANDLE_STMT, hdbc, &stmt_ );
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO ){
		LOG_ERR( LOG_SERVICE( "instance" )->Log("%s - %u", __FUNCTION__, __LINE__) );
		return 0;
	}

	return 1;
}

size_t ODBC_DBResultSet::getAffectedCount(){
	SQLLEN row_count = 0;
	SQLRETURN ret = ::SQLRowCount( stmt_, &row_count );
	return (size_t)row_count;
}

int ODBC_DBResultSet::setByte( char* data ){
	bind_col_idx_++;

	SQLLEN ret = 0;
	SQLRETURN h = SQLBindCol( stmt_, bind_col_idx_, SQL_C_CHAR, data, sizeof( char ), &ret );

	if( ( h == SQL_ERROR ) || ( h == SQL_INVALID_HANDLE ) )
		return 0;
	return 1;
}

int ODBC_DBResultSet::set2Byte( short* data ){
	bind_col_idx_++;

	SQLLEN ret = 0;
	SQLRETURN h = SQLBindCol( stmt_, bind_col_idx_, SQL_C_SHORT, data, sizeof( short ), &ret );

	if( ( h == SQL_ERROR ) || ( h == SQL_INVALID_HANDLE ) )
		return 0;
	return 1;
}

int ODBC_DBResultSet::set4Byte( int* data ){
	bind_col_idx_++;

	SQLLEN ret = 0;
	SQLRETURN h = SQLBindCol( stmt_, bind_col_idx_, SQL_C_LONG, data, sizeof( int ), &ret );

	if( ( h == SQL_ERROR ) || ( h == SQL_INVALID_HANDLE ) )
		return 0;
	return 1;
}

int ODBC_DBResultSet::set8Byte( __int64* data ){
	bind_col_idx_++;

	SQLLEN ret = 0;
	SQLRETURN h = SQLBindCol( stmt_, bind_col_idx_, SQL_C_SBIGINT, data, sizeof( __int64 ), &ret );

	if( ( h == SQL_ERROR ) || ( h == SQL_INVALID_HANDLE ) )
		return 0;
	return 1;
}

int ODBC_DBResultSet::setString( char* data, size_t size ){
	bind_col_idx_++;

	SQLLEN ret = 0;
	SQLRETURN h = SQLBindCol( stmt_, bind_col_idx_, SQL_C_CHAR, data, size, &ret );

	if( ( h == SQL_ERROR ) || ( h == SQL_INVALID_HANDLE ) )
		return 0;
	return 1;
}

int ODBC_DBResultSet::get_resultset_desc( void* handle, DBTableDescription& table_desc ){
	short count = 0;
	SQLRETURN ret = SQLNumResultCols( stmt_, &count );

	if(! count )
		return 0;
	
	char name[ 256 ];
	memset( name, 0, sizeof( char ) * 256 );
	short nameLengthPtr = 0;
	short type = 0;
	SQLULEN size = 0;
	short decimalDigitPtr = 0;
	short nullable = 0;	

	for( short i = 0 ; i < count ; i++ ){
		ret = SQLDescribeCol( \
			stmt_, //handle
			i + 1, // number
			(unsigned char*)name, //name
			256, //buffer length
			&nameLengthPtr, //namelengthptr
			&type, //DataType
			&size, //size ptr
			&decimalDigitPtr, //decimal digitptr
			&nullable //nullable
			);

		if( type == SQL_VARCHAR ){
			type = SQL_CHAR;
			size += 1;
		}
		else if( type == SQL_INTEGER )
			size = 4;
		else if( type == SQL_SMALLINT )
			size = 2;
		else if( type == SQL_CHAR )
			size += 1;
		else if( type == SQL_FLOAT )
			type = SQL_DOUBLE;
		else if( type == SQL_BIGINT )
			size = 8;			
		else if( type == SQL_TYPE_TIMESTAMP ){
			type = SQL_CHAR;
			size = DEF_DATE_STR_SIZE;
		}
		else if( type == SQL_TIMESTAMP ){
			type = SQL_CHAR;
			size = DEF_DATE_STR_SIZE;
		}
		else if( type == SQL_NUMERIC ){
			type = SQL_CHAR;
			size += 1;
		}
		else if( type == SQL_DECIMAL ){
			type = SQL_CHAR;
			size += 1;
		}
		else if( type == SQL_NULL_DATA ){
			//for mysql desc table
			type = SQL_CHAR;
			size = DEF_NULL_TYPE_STR_SIZE;
		}
		else if( type == -8 ){
			//err for postgres char
			type = SQL_CHAR;
			size += 1;
		}
		else if( type == SQL_UNKNOWN_TYPE ){			
			return 0;
		}

		table_desc.addColumnInfo( name, type, 0, 0, size, decimalDigitPtr, 0, nullable, \
			0, 0, type, 0, 0, 0, 0 );
	}

	return 0;
}